package cn.q3c.parse;

import java.io.File;
import java.util.ArrayList;
import java.util.Date;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.text.ParseException;
import java.text.SimpleDateFormat;

import org.apache.commons.lang.time.DateFormatUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.time.DateUtils;
import org.apache.log4j.Logger;

import org.apache.commons.configuration.ConfigurationException;
import org.apache.commons.configuration.PropertiesConfiguration;

import cn.keyvalue.ccf.common.util.ObjectUtils;
import cn.q3c.download.api.DownloadAPI;
import cn.q3c.download.commons.DownloadLog;
import cn.q3c.parse.base.BaseParse;
import cn.q3c.parse.base.BaseProcess;
import cn.q3c.parse.commons.Configuration;
import cn.q3c.parse.commons.ConfigProject;

/**
 * 系统后台启动
 * 
 * @author wangxinning
 * 
 */
public class Run {

	private final static Logger logger = Logger.getLogger(Run.class);

	// 爬虫对象map
	private static Map<String, Object> parseAndProcessMap = new HashMap<String, Object>();
	// 爬去时间记录
	//private static Map<String, Long> parseAndProcessTimes = new HashMap<String, Long>();

	public static void main(String[] args) {

		// 1.无限循环中。此程序单进程
		while (true) {
			
			// 2.获取全部项目(动态更新)
			List<ConfigProject> projectList = Configuration.getInstance()
					.getConfigProjectList();

			// 3.循环项目
			for (ConfigProject project : projectList) {
				try
				{
					processProject(project);
				}
				catch( Exception e )
				{
					logger.error("项目处理异常，" + project.getName(), e);
				}
			}

			// 4.一轮完成，停顿一会
			try {
				Thread.sleep(DateUtils.MILLIS_PER_SECOND
						* Configuration.getInstance().getWaitTime());
				logger.info("...");
			} catch (InterruptedException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
		}
	}

	private static BaseParse getParse(ConfigProject project) {
		String key = project.getName() + project.getParseclass();

		BaseParse parse = (BaseParse) parseAndProcessMap.get(key);
		if (parse == null) {
			try {
				parse = (BaseParse) (Class.forName(project.getParseclass())
						.newInstance());

				parseAndProcessMap.put(key, parse);

			} catch (Exception e) {
				logger.error("动态加载解析类异常 " + project.getParseclass(), e);
			}
		}

		return parse;
	}

	private static List<BaseProcess> getProcess(ConfigProject project) {
		
		List<BaseProcess> retArray = new ArrayList<BaseProcess>();
		String[] clc = project.getProcessclassList();
		logger.debug("处理类：" + ArrayUtils.toString(clc));
		
		for( String className:clc )
		{
			String key = project.getName() + className;
			BaseProcess parse = (BaseProcess) parseAndProcessMap.get(key);
			
			if (parse == null) {
				try {
					parse = (BaseProcess) (Class.forName(className)
							.newInstance());
					parseAndProcessMap.put(key, parse);
					
					//retArray = ArrayUtils.add((BaseProcess)retArray, parse);
				} catch (Exception e) {
					logger.error("动态加载解析类异常 " + className, e);
				}
			}
			
			retArray.add(parse);
		}
		
		return retArray;
	}

	/**
	 * 处理下载项目的总方法，可能迁出 建立线程池，循环加入链接，无需理会线程池是否结束
	 * 
	 * @param project
	 * @throws ParseException 
	 * @throws ConfigurationException 
	 */
	private static void processProject(ConfigProject project) throws ParseException, ConfigurationException {
		
		// 0.非活动状态直接跳出
		if( !project.isActive() )
		{
			logger.debug("非激活状态，不进行解析处理  " + project.getName() + " "
					+ project.getDescription());
			return;
		}
				
		logger.debug("处理项目：" + project);
		
		// 1.获取爬虫部分
		BaseParse parse = getParse(project);
		//logger.debug("parse：" + parse);
		List<BaseProcess> processArray = getProcess(project);
		//logger.debug("process：" + processArray);
		if (parse != null && !ObjectUtils.isEmptyList(processArray)) {
			// 计算时间范围
			Long toDate = System.currentTimeMillis();
			Long fromDate = getFromTime( project ).getTime();

			logger.debug("fromDate：" + new Date(fromDate));
			logger.debug("toDate：" + new Date(toDate));
			
			try {
				// 获取待处理的文件
				List<DownloadLog> downloadLogList = DownloadAPI
						.getDownloadLogList(project.getDownloadProjectName(),
								new Date(fromDate), new Date(toDate));
				
				//logger.debug("downloadLogList：" + downloadLogList);

				// 处理文件
				if (!ObjectUtils.isEmptyList(downloadLogList)) {
					
					//根据配置缩减
					if( project.getMaxprocesscount() > 0 && project.getMaxprocesscount() < downloadLogList.size() )
					{
						downloadLogList = downloadLogList.subList(0, project.getMaxprocesscount());
						logger.debug("缩短文件列表长度=" + project.getMaxprocesscount());
					}
					
					for (DownloadLog downloadLog : downloadLogList) {
						//解析
						
						//logger.debug("downloadLogList=" + downloadLog);

						
						Object obj = parse.parse(downloadLog.getUrl(),
								downloadLog.getFile(),downloadLog.getParentUrl(),downloadLog.getParentFile());
						//处理
						if( obj != null )
						{
							for( BaseProcess process:processArray )
							{
								process.process(obj);
							}							
						}
					}
				}

			} catch (Exception e) {
				logger.error("处理文件出现异常", e);
			}
			
			saveConfigFile( project, new Date(toDate) );
		}
	}
	
	
	//项目信息 截至时间
	private static void saveConfigFile( ConfigProject project, Date toDate )
	{
		try
		{
			PropertiesConfiguration config = new PropertiesConfiguration( getConfigFile(project) );
			config.setProperty("last.time", DateFormatUtils.format(toDate, "yyyy-MM-dd HH:mm:ss"));
			config.save();
		}
		catch( Exception e )
		{
			logger.error(project.getName() + "处理数据写入异常", e);
		}
	}
	
	
	private static File getConfigFile( ConfigProject project )
	{
		String configFileStr = Configuration.getInstance().getStorePath() + project.getName() + ".properties";
		return new File( configFileStr );
	}
	
	
	/**
	 * 项目起始时间
	 * 没有-间隔
	 * 有读取配置文件
	 * @param project
	 * @return
	 * @throws ParseException 
	 * @throws ConfigurationException 
	 */
	private static Date getFromTime( ConfigProject project ) throws ParseException, ConfigurationException
	{
		File file = getConfigFile( project );
		if( !file.exists() )
		{
			Long fromDate = System.currentTimeMillis() - project.getMaxtimelimit()
						* DateUtils.MILLIS_PER_MINUTE;
			return new Date( fromDate );
		}
		else
		{
			PropertiesConfiguration config = new PropertiesConfiguration( file );
			String format = "yyyy-MM-dd HH:mm:ss";
			String str = config.getString("last.time");
			SimpleDateFormat sdf = new SimpleDateFormat( format );
			return sdf.parse(str);
		}
	}
}